#ifndef GENERATION_H_
#define GENERATION_H_

#include<QList>

class AbstractChromosomeFactory;
class Chromosome;
class SelectionStrategy;

/**
  * Class that represents one generation.
  * Contains list of chromosomes.
  * @author Łukasz Szybka
  */
class Generation
{
public:
    /**
      * Constructor
      */
    Generation();
    Generation(int generationSize, AbstractChromosomeFactory* chromosomeFactory);
    Generation(const Generation& other);
    ~Generation();

    Generation& operator=(const Generation& other);

    /**
      * Adds given chromosome to Generation::chromosomeList
      * @param toAdd Chromosome to add
      */
    void addChromosome(Chromosome* toAdd);
    /**
      * @return Size of generation
      */
    int size() const;
    /**
      * @return Sum of fitness of all chromosomes in generation
      */
    double totalFitness() const;
    /**
      * @return Fitness of worst chromosome in generation
      */
    double minFitness() const;
    /**
      * @return Fitness of best chromosome in generation
      */
    double maxFitness() const;

    /**
      * @return Pointer that should be copied using duplicate()
      */
    Chromosome* getProcreator(SelectionStrategy* selectionStrategy);

    /**
      * Performs crossover in generation
      * @param crossoverProb Crossover probability
      */
    void performCrossOver(double crossoverProb);
    /**
      * Performs mutation in generation
      * @param mutationProb Mutation probability
      */
    void performMutation(double mutationProb);
    /**
      * Performs additional operators in generation
      * @param additionalOperatorProb1 Probability of first additional operator
      * @param additionalOperatorProb2 Probability of second additional operator
      */
    void performAdditionalOperators(double additionalOperatorProb1, double additionalOperatorProb2);

    /**
      * Returns best chromosome in generation
      * @return Pointer that should be copied using duplicate()
      */
    Chromosome* getBestRepresentative() const;
    /**
      * Replace chromosome at given index with given chromosome
      * This method doesn't sort the list of chromosomes!
      * Generation::chromosomeList should be sorted using sort() after calling that method
      * @param index Index of chromosome to replace
      * @param toAdd Chromosome to add
      */
    void replaceChromosome(int index, Chromosome* toAdd);
    /**
      * @return List of chromosome idexes that are duplicated
      */
    QList<int> findDuplicates();

    /**
      * @param index Chromosome index
      * @return Reference to chromosome at given index from Generation::chromosomeList
      */
    Chromosome& operator[](int index);
    /**
      * Sorts Generation::chromosomeList
      */
    void sort();

    friend QDebug operator<<(QDebug dbg, const Generation &gen);

protected:
    /**
      * Fills Generation::chromosomeList with chromosomes
      * @param generationSize Amount of chromosomes that will be added
      */
    void randomChromosomes(int generationSize, AbstractChromosomeFactory* chromosomeFactory);
    /**
      * List of all chromosomes in generation
      */
    QList<Chromosome*> chromosomeList;

private:
};

#endif /*GENERATION_H_*/
